from django import http
from django.shortcuts import render

# Create your views here.cl
from django.views import View
import  json

from django_redis import get_redis_connection

from carts import constants
from goods.models import SKU
from meiduo_mall.utils import meiduo_json
from meiduo_mall.utils.response_code import RETCODE

#购物车页面数据的添加
class CartView(View):
    def post(self,request):
        # 先向购物车添加数据
        parm_dict = json.loads(request.body.decode())
        sku_id = parm_dict.get('sku_id')
        count = parm_dict.get('count')
        #判断非空
        if not all([sku_id,count]):
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'参数不齐'
            })
        # 判断sku_id的合法性
        try:
            sku = SKU.objects.get(pk = sku_id,is_launched=True)
            # print(sku)
        except:
            return http.JsonResponse({
                'code': RETCODE.PARAMERR,
                'errmsg': '该库存商品已经下架'
            })
        #将数量强转整数类型
        try:
            count = int(count)
        except:
            return http.JsonResponse({
                'code': RETCODE.PARAMERR,
                'errmsg': '该数量参数类型不符合要求'

            })
        if count <=0:
            return http.JsonResponse({
                'code': RETCODE.PARAMERR,
                'errmsg': '添加商品的数量必须大于０'
            })
        if sku.stock <count:
            return http.JsonResponse({
                'code': RETCODE.PARAMERR,
                'errmsg': '抱歉，你所选的该类商品的数量大于库存量，库存量不足,'
            })
        # 处理
        response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})
        user = request.user
        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            redis_pl = redis_cli.pipeline()
            #为了让数据方便读取，将sku_id count 储存在hash中，实际已经把数据的建和值转化为字符串
            redis_pl.hset('cart%d'%user.id,sku_id,count)
            #在set中储存被选中的商品id，
            redis_pl.sadd('selected%d'%user.id,sku_id)
            redis_pl.execute()
        #在用户没有登陆的情况下设置在cookie 中储存，
        else:
            # 第一读取cookie中的购物车信息,在你浏览网站cookie只是缓存了临时会话，在退出的时候自动删除
            cart_str = request.COOKIES.get('cart')
            if cart_str is None:
                cart_dict = {}
            else:
                cart_dict = meiduo_json.loads(cart_str) #把字符串转成字典解密
            #总之不管空还是有数据，都会建立一个字典，用于添加新的数据
            if sku_id not in cart_dict:#如果这个商品不在购物车中,就添加到字典
                cart_dict[sku_id]= {
                    'count':count,
                    'selected':True
                }
            else:
                cart_dict[sku_id]['count'] = cart_dict[sku_id]['count']  + count
            #表示如果购物车存在此数据，需要进行数量的增加
              #
              # '''{
              #          'cart": cart_str ={
              #                  sku_id:{
              #                      'count'：数量,
              #                      'selected':选中状态
              #                  },
              #                  ...
              #              }
              #              }

            #下面表示加密后保存到cookie 中,先创建一个响应对象

            cart_str = meiduo_json.dumps(cart_dict)
            response.set_cookie('cart',cart_str,constants.CART_EXPIRES)

        return response
# 增加的逻辑,如果用户已经登陆，将数据保存在redis 否则cookie中保存- 先读取，再转字典解密－添加－转字符串加密-保存
#查询购物车的数据,展示在前端页面
    def get(self,request):
        user = request.user
        cart_dict = {}
        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            #hash的查询出来的是字典{sku_id:count}
            cart_redis_dict = redis_cli.hgetall('cart%d'%user.id)
            #set的查询出来是列表　有多个字符传
            selecteds = redis_cli.smembers('selected%d'%user.id)
             #从redis 读出来的数据都是字符串,遍历数据以商品编号为建，数量和选中为值的字典
            for sku_id ,count in cart_redis_dict.items():
                cart_dict[int(sku_id)]={
                    'count':int(count),
                    'selected':sku_id in selecteds
                    # '表示查询出来的商品如果在列表selected中就是ＴＵＲＬ，如不是则ＦＡＬＳＥ
                }
        else:
            cart_str = request.COOKIES.get('cart')
            if cart_str is None:
                context={
                    'cart_skus': []
                }
                return render(request,'cart.html',context)
            cart_dict = meiduo_json.loads(cart_str)
            # print(cart_dict)
        #从cookie 中读取数据
        #查询购物车所有的商品，转化成前端需要的格式
        skus = SKU.objects.filter(pk__in = cart_dict.keys())   #[1,2,3,..]表示从字典总拿到的数据
        sku_list =[]
        for sku in skus:
            sku_list.append({
            'id': sku.id,
            'name': sku.name,
            'default_image_url': sku.default_image.url,
            'price': str(sku.price),  # js中没有Decimal类型，所以需要转字符串
            'count': cart_dict[sku.id]['count'],  #库存商品里面没有数量需要在字典里面获取
            'selected': str(cart_dict[sku.id]['selected'])  # js中的bool类型是true、false，而pytho

            })

        context = {'cart_skus': sku_list }
        return render(request,'cart.html',context)

#总结查询１，判断用户是否登陆，登陆后创建数据库的链接，对hash和set进行查询，查询的数据是bｕyte类型,hash拿出来的是字典,需要进行拆包遍历
#遍历的目的为了让sku_id为建，count和selected为值，建立一个字典，最后以购物车商品id为基准，通过查询库存商品

    def put(self,request):
        #接收
        parms_dict =json.loads(request.body.decode())
        sku_id = parms_dict.get('sku_id')
        count = parms_dict.get('count')
        selected = parms_dict.get('selected',True)
        #验证
        #非空验证
        if not all ([sku_id,count]):
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'参数不全'
            })
        #判断合法性
        try:

            sku = SKU.objects.get(pk = sku_id,is_launched=True)
        except:
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'该商品在库存中不存在，已经下架'

            })
        #强转count 类型
        try:
            count =int(count)
        except:
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'该参数类型错误'
            })
        #对库存商量判断
        if count <=0:
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'你选择的购物车商品数量不符合要求'
            })
        #对库存商品量进行判断
        if sku.stock<count:
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'该商品量库存不足'
            })
        if not isinstance(selected,bool):
            return http.JsonResponse({
                'code':RETCODE.PARAMERR,
                'errmsg':'选中状态错误'
            })
        #---------到此参数验证完毕
        # 处理

        # 处理
        user = request.user
        response = http.JsonResponse({
            'code': RETCODE.OK,
            'errmsg': 'ok',
            'cart_sku': {
                'id': sku_id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': str(sku.price),
                'count': count,
                'selected': str(selected)
            }
        })

        #判断用户是否登陆
        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            redis_pl = redis_cli.pipeline()
            # 修改hash中的数据
            redis_pl.hset('cart%d' % user.id, sku_id, count)
            # 修改set中的选中状态
            if selected:
                # 如果选中则向集合中添加sku_id
                redis_pl.sadd('selected%d' % user.id, sku_id)
            else:
                # 如果不选中则从集合中删除sku_id
                redis_pl.srem('selected%d' % user.id, sku_id)
            redis_pl.execute()
        else:
            # 1.读取cookie中购物车数据
            cart_str = request.COOKIES.get('cart')
            if cart_str is None:#字符串可以用None判断
                cart_dict = {}
            else:
                cart_dict = meiduo_json.loads(cart_str)
            # 2.修改,如果字典里面有数据就覆盖，没有就增加
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 3.写cookie，将cookie转化加密转化为字符串，以cart作为键储存
            cart_str = meiduo_json.dumps(cart_dict)
            response.set_cookie('cart', cart_str, max_age=constants.CART_EXPIRES)

            # 响应
        return response


#修改的逻辑，首先判断用户是否登陆，如果登陆，从hash中得到数据，更改数量，从set中拿到数据，判断是否选中，选中就保存在集合中,
# 如果没有被选中就删除,响应数据

#删除的逻辑
    def delete(self,request):
        param_dict = json.loads(request.body.decode())
        sku_id = param_dict.get('sku_id')
        # 验证
        if not all([sku_id]):
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'参数不齐'})
        try:
            sku = SKU.objects.get(pk = sku_id,is_launched=True)
        except:
            return http.JsonResponse({'code':RETCODE.PARAMERR,'errmsg':'该商品已经下架，库存暂无此商品'})
        # 处理
        user = request.user
        response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})
        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            redis_pl = redis_cli.pipeline()
            #删除hash中的商品ｉｄ
            redis_pl.hdel('cart%d'% user.id,sku_id)
            #删除set中的selected选中的商品Ｉｄ
            redis_pl.srem('selected%d'% user.id,sku_id)
            #执行任务
            redis_pl.execute()

        else:
            cart_str = request.COOKIES.get('cart')
            if cart_str is None:
                cart_dict = {}
            else:
                cart_dict = meiduo_json.loads(cart_str)
            if sku_id in cart_dict:
                del cart_dict[sku_id]
            cart_str = meiduo_json.dumps(cart_dict)
            response.set_cookie('cart',cart_str,constants.CART_EXPIRES)
        return response
#全选或者全不选
class CartSelectView(View):
    def put(self, request):
        # 设置购物车中的商品全选中或全不选中

        # 接收
        param_dict = json.loads(request.body.decode())
        selected = param_dict.get('selected', True)

        # 验证
        if not isinstance(selected, bool):
            return http.JsonResponse({'code': RETCODE.PARAMERR, 'errmsg': '选中状态不正确'})

        # 处理
        user = request.user
        response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})
        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            # 修改set
            if selected:
                # 在hash中查询当前用户的所有库存商品
                sku_ids = redis_cli.hkeys('cart%d' % user.id)  # [1,2,3,4]
                # 加入set中
                redis_cli.sadd('selected%d' % user.id, *sku_ids)
            else:
                redis_cli.delete('selected%d' % user.id)
        else:
            # 1.读取cookie中的购物车数据
            cart_str = request.COOKIES.get('cart')
            if cart_str is None:
                cart_dict = {}
            else:
                cart_dict = meiduo_json.loads(cart_str)
            # 2.遍历字典，修改选中属性
            for sku_id, cart in cart_dict.items():
                cart['selected'] = selected
            # 3.写cookie
            cart_str = meiduo_json.dumps(cart_dict)
            response.set_cookie('cart', cart_str, max_age=constants.CART_EXPIRES)

        # 响应
        return response

#建立一个类视图，购物车列表－－我的购物车
class CartsSimpleView(View):
    def get(self,request):
        user = request.user
        #链接数据库判断用户是否登陆
        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            cart_dict =redis_cli.hgetall('cart%d'%user.id)
            #从redis 中得到的数据是字节类型bytes
            cart_dict = {int(sku_id):int(count) for sku_id,count in cart_dict.items()}
            #{sku_id:count}
        else:
            cart_str = request.COOKIES .get('cart')
            if cart_str is None:
                cart_dict = {}
            else:
                cart_dict = meiduo_json.loads(cart_str)
                #{sku_id:{'count':count},'selected':selected} －－cookie拿出的数据不需要转化
                cart_dict = {sku_id: cart['count'] for sku_id, cart in cart_dict.items()}
        #查询库存商品中购物车的商品是否还在，没有下架
        skus = SKU.objects.filter(pk__in =cart_dict.keys(),is_launched=True)
        sku_list = []
        #遍历转化为前端需要的数据
        for sku in skus:
            sku_list.append({
                'id':sku.id,
                'name':sku.name,
                'count':cart_dict[sku.id],#sku 没有这个数量，表示当前商品的ｓｋｕ_id =sku.id
                'default_image_url':sku.default_image.url

            })

        return http.JsonResponse({
            'code':RETCODE.OK,
            'errmsg':'ok',
            'cart_skus':sku_list

        })

#这一部分主要设计购物车的增删改查，以及全选中和都不选中，－－我的购物车的列表显示－－－－这个应用下建立了一个合并购物车，
#程序设计，当点击结算时购物车数据删除，数据提交到订单，用户在没有登陆时，数据保存在cookie 中，当用户登陆后数据合并在redis中，储存


